package com.aier.service.invoice.impl;

import com.aier.bean.common.CommonCode;
import com.aier.bean.common.GlobalCode;
import com.aier.bean.foreign.ForeignBase;
import com.aier.bean.forwarder.ForwarderCode;
import com.aier.bean.forwarder.FreightForwarder;
import com.aier.bean.invoice.HengdaInvoice;
import com.aier.exception.CastException;
import com.aier.mapper.invoice.HengdaInvoiceMapper;
import com.aier.service.foreign.ForeignBaseService;
import com.aier.service.forwarder.FreightForwarderService;
import com.aier.service.invoice.HengdaInvoiceService;
import com.aier.utils.DateUtils;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;


/** 恒达发票信息service **/
@Service
public class HengdaInvoiceServiceImpl implements HengdaInvoiceService {

    @Autowired
    private HengdaInvoiceMapper invoiceMapper;

    @Autowired
    private ForeignBaseService foreignBaseService;

    @Autowired
    private FreightForwarderService freightForwarderService;

    @Override
    public void saveHengdaInvoice(HengdaInvoice hengdaInvoice) {
        String fbaCode = hengdaInvoice.getFbaCode();
        ForeignBase foreignBase = foreignBaseService.getForeignBaseByFbaCode(fbaCode);
        if (foreignBase == null) {
            CastException.cast(GlobalCode.FBA_IS_EMPTY_OR_FOREIGN_NOT);
        }
        invoiceMapper.insert(hengdaInvoice);
    }

    @Override
    public HengdaInvoice getHengdaInvoiceByFba(String fbaCode) {
        QueryWrapper<HengdaInvoice> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(HengdaInvoice::getFbaCode,fbaCode);
        return invoiceMapper.selectOne(queryWrapper);
    }

    @Override
    public void modifyHengdaInvoice(HengdaInvoice hengdaInvoice) {
        QueryWrapper<HengdaInvoice> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(HengdaInvoice::getFbaCode,hengdaInvoice.getFbaCode());
        invoiceMapper.update(hengdaInvoice,queryWrapper);
    }

    @Override
    public void removeHengdaInvoice(String fbaCode) {
        QueryWrapper<HengdaInvoice> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(HengdaInvoice::getFbaCode,fbaCode);
        invoiceMapper.delete(queryWrapper);
    }

    @Override
    public List<HengdaInvoice> getHengdaInvoiceByStaffId(String staffId) {
        List<ForeignBase> foreignBaseList = foreignBaseService.getForeignBaseByStaffIdNotShipment(staffId);
        List<HengdaInvoice> hengdaInvoiceList = new ArrayList<>();
        foreignBaseList.stream().forEach(foreignBase -> {
            FreightForwarder freightForwarder = freightForwarderService.getFreightForwarderByFbaAndForwarderCode(foreignBase.getFbaCode(), ForwarderCode.HENG_DA.getCode());
            HengdaInvoice hengdaInvoice = new HengdaInvoice(foreignBase,freightForwarder);
            HengdaInvoice hengdaInvoiceByFba = getHengdaInvoiceByFba(foreignBase.getFbaCode());
            /** 不为空则表示数据库已保存过历史记录 **/
            if (hengdaInvoiceByFba != null){
                copyFiledValue(hengdaInvoiceByFba,hengdaInvoice);
            }
            calculateField(hengdaInvoice);
            hengdaInvoiceList.add(hengdaInvoice);
        });
        return hengdaInvoiceList;
    }

    @Override
    public void modifyOrInsertHengdaInvoice(HengdaInvoice hengdaInvoice) {
        String fbaCode = hengdaInvoice.getFbaCode();
        if (fbaCode == null || fbaCode.isEmpty()){
            CastException.cast(GlobalCode.FBA_IS_EMPTY);
        }
        HengdaInvoice invoiceByFba = getHengdaInvoiceByFba(fbaCode);
        /** 数据库有数据则修改 **/
        if (invoiceByFba != null){
            modifyHengdaInvoice(hengdaInvoice);
        }else {
            /** 数据库无数据则添加 **/
            saveHengdaInvoice(hengdaInvoice);
        }
    }


    @Override
    public ZipOutputStream batchExportCargoOrderTmpZip(HttpServletRequest request, HttpServletResponse response,List<HengdaInvoice> hengdaInvoiceList) throws UnsupportedEncodingException {
        /** 获取模版文件路径 **/
        String templatePath = "exceltemplate/hengda_template.xlsx";

        /** zip文件的名字 **/
        String zipFileName = DateUtils.getCurrentDate("yyyyMMDD") + "-唛头.zip";

        /** 响应头的设置 **/
        response.reset();
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/zip");
        /** 解决跨域 **/
        response.addHeader("Access-Control-Allow-Origin", "*");

        response.setHeader("ZIP-FILE-NAME",zipFileName);
        response.setHeader("Content-Disposition", "attachment; filename=\""+zipFileName+"\"");
        /** 设置压缩流：直接写入response，实现边压缩边下载 **/
        ZipOutputStream zipos = null;
        try {
            zipos = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
            zipos.setMethod(ZipOutputStream.DEFLATED); //设置压缩方法
        } catch (Exception e) {
            e.printStackTrace();
        }
        /** 循环将文件写入压缩流 **/
        DataOutputStream os = null;
        
        for (HengdaInvoice hengdaInvoice : hengdaInvoiceList) {
            /** 封装模版中的内容，获取文件输入流 **/
            InputStream tmpFileStream = null;
            try {
                tmpFileStream = getFillFileInputStream(hengdaInvoice, templatePath, response);
            } catch (Exception e) {
                e.printStackTrace();
                CastException.cast(GlobalCode.TEMPLATE_FILL_FAIL);
            }
            String selfTaxed = hengdaInvoice.getSelfTaxed() != null && hengdaInvoice.getSelfTaxed().equals(CommonCode.SELF_TAXED) ? "自税" : "包税";
            /** 生成的excel名字 **/
            String fileName = hengdaInvoice.getWarehouseCode() + "-" + hengdaInvoice.getSku() + "-" + hengdaInvoice.getBoxNum().intValue() + "件-" + selfTaxed + ".xlsx";
            System.out.println(fileName);
            try {
                /** 添加ZipEntry，并ZipEntry中写入文件流 **/
                zipos.putNextEntry(new ZipEntry(fileName));
                os = new DataOutputStream(zipos);
                byte[] b = new byte[100];
                int length = 0;
                while ((length = tmpFileStream.read(b)) != -1) {
                    os.write(b, 0, length);
                }
                tmpFileStream.close();
                zipos.closeEntry();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (tmpFileStream != null) {
                    try {
                        tmpFileStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        //关闭流
        try {
            os.flush();
            os.close();
            zipos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return zipos;
    }

    @Override
    public InputStream getFillFileInputStream(HengdaInvoice hengdaInvoice,String templatePath, HttpServletResponse response) throws IOException {
        /** 利用excel模版形式填充数据 **/
        ExcelWriter excelWriter = null;
        InputStream inputStream = null;
        InputStream returnInputStream = null;
        try {
            ClassPathResource classPathResource = new ClassPathResource(templatePath);
            inputStream = new BufferedInputStream(classPathResource.getInputStream());
            /** outputStream：要导出的文件的输出流 **/
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            /** 定义写入策略 **/
            excelWriter = EasyExcel
                    .write(outputStream)
                    .withTemplate(inputStream)
                    .autoCloseStream(Boolean.TRUE)
                    .build();
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            /** 填充数据 **/
            excelWriter.fill(hengdaInvoice, writeSheet);

            /** 如果模版里包含公式计算，则需要设置公式自动计算 **/
            excelWriter.writeContext().writeWorkbookHolder().getWorkbook().setForceFormulaRecalculation(true);
            excelWriter.finish();
            /** 返回组装好的输入流 **/
            returnInputStream = new ByteArrayInputStream(outputStream.toByteArray());
        } catch (Exception e) {
            e.printStackTrace();
            CastException.cast(GlobalCode.TEMPLATE_FILL_FAIL);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    CastException.cast(GlobalCode.TEMPLATE_FILL_FAIL);
                }
            }
        }
        return returnInputStream;
    }



    /**
     * 计算对象内的一些属性值
     * @param hengdaInvoice
     */
    private void calculateField(HengdaInvoice hengdaInvoice){
        /** 计算总数 **/
        hengdaInvoice.setTotalQty(hengdaInvoice.getBoxNum().multiply(hengdaInvoice.getPerBoxQty()));
        /** 计算总重量 **/
        hengdaInvoice.setTotalWeight(
                hengdaInvoice.getWeight()
                        .multiply(hengdaInvoice.getBoxNum())
                        .setScale(2, RoundingMode.HALF_UP));
        /** 计算总体积 **/
        hengdaInvoice.setTotalVolumetric(
                hengdaInvoice.getBoxLength()
                        .multiply(hengdaInvoice.getBoxWidth())
                        .multiply(hengdaInvoice.getBoxHeight())
                        .multiply(BigDecimal.valueOf(0.000001))
                        .multiply(hengdaInvoice.getBoxNum())
                        .setScale(2, RoundingMode.HALF_UP)
        );

        /** 预计箱数 **/
        hengdaInvoice.setExpectBoxNum(hengdaInvoice.getTotalQty());
        /** 预计重量 **/
        hengdaInvoice.setExpectWeight(hengdaInvoice.getTotalWeight());
        /** 预计体积 **/
        hengdaInvoice.setExpectBulk(hengdaInvoice.getTotalVolumetric());
        /** 计算单价 **/
        hengdaInvoice.setDeclaredUnitPrice(BigDecimal.valueOf(167)
                .multiply(hengdaInvoice.getTotalVolumetric())
                .divide(hengdaInvoice.getBoxNum()
                        .multiply(hengdaInvoice.getPerBoxQty()),2, RoundingMode.HALF_UP)
                .setScale(2, RoundingMode.HALF_UP));
        /** 计算总价 **/
        hengdaInvoice.setTotalPrice(
                hengdaInvoice.getDeclaredUnitPrice()
                        .multiply(hengdaInvoice.getBoxNum())
                        .setScale(2, RoundingMode.HALF_UP));

        /** 计算采购总价 **/
        hengdaInvoice.setPurchaseTotalPrice(hengdaInvoice.getDeclaredUnitPrice()
                .multiply(BigDecimal.valueOf(1.5))
                .multiply(BigDecimal.valueOf(7.2))
                .setScale(2, RoundingMode.HALF_UP));
    }

    /**
     * 复制属性值
     * @param from 源实例
     * @param to 目标实例
     */
    private void copyFiledValue(HengdaInvoice from,HengdaInvoice to){
        to.setUnit(from.getUnit());
        to.setBusinessType(from.getBusinessType());
        to.setDeclarationType(from.getDeclarationType());
        to.setTransportChannel(from.getTransportChannel());
        to.setBrandName(from.getBrandName());
        to.setChineBrandName(from.getChineBrandName());
        to.setEnBrandName(from.getEnBrandName());
        to.setBrand(from.getBrand());
        to.setMaterial(from.getMaterial());
        to.setUseScope(from.getUseScope());
        to.setCustomsCode(from.getCustomsCode());
        to.setCharacteristics(from.getCharacteristics());
        to.setPurchasePrice(from.getPurchasePrice());
        to.setPurchaseTotalPrice(from.getPurchaseTotalPrice());
    }
}
